package com.jizhi.onework.utils;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis 工具类
 *
 * @author hzhang7
 */
@Configuration
public class RedisUtil {

    private static RedisTemplate redisTemplate;

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        redisTemplate = template;
        return template;
    }

    /**
     * 实现命令：TTL key，以秒为单位，返回给定 key的剩余生存时间(TTL, time to live)。
     *
     * @param key
     * @return
     */
    public static long ttl(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 实现命令：expire 设置过期时间，单位秒
     *
     * @param key
     * @return
     */
    public static void expire(String key, long timeout) {
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令：INCR key，增加key一次
     *
     * @param key
     * @return
     */
    public static long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 实现命令：KEYS pattern，查找所有符合给定模式 pattern的 key
     */
    public static Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 实现命令：DEL key，删除一个key
     *
     * @param key
     */
    public static void del(String key) {
        redisTemplate.delete(key);
    }

    // String（字符串）

    /**
     * 实现命令：SET key value，设置一个key-value（将字符串值 value关联到 key）
     *
     * @param key
     * @param value
     */
    public static void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 实现命令：SET key value EX seconds，设置key-value和超时时间（秒）
     *
     * @param key
     * @param value
     * @param timeout （以秒为单位）
     */
    public static void set(String key, String value, long timeout) {
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令：GET key，返回 key所关联的字符串值。
     *
     * @param key
     * @return value
     */
    public static String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    public static ValueOperations getValueOperations() {
        return redisTemplate.opsForValue();
    }

    /**
     * 获取原来key键对应的值并重新赋新值。
     *
     * @param key
     * @param value
     * @return
     */
    public static void getAndSet(String key, Object value) {
        redisTemplate.opsForValue().getAndSet(key, value);
    }

    // Hash（哈希表）

    /**
     * 实现命令：HSET key field value，将哈希表 key中的域 field的值设为 value
     *
     * @param key
     * @param field
     * @param value
     */
    public static void hset(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, value);
    }

    /**
     * 实现命令：HGET key field，返回哈希表 key中给定域 field的值
     *
     * @param key
     * @param field
     * @return
     */
    public static String hget(String key, String field) {
        return (String) redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 实现命令：HDEL key field [field ...]，删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。
     *
     * @param key
     * @param fields
     */
    public static void hdel(String key, Object... fields) {
        redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 实现命令：HGETALL key，返回哈希表 key中，所有的域和值。
     *
     * @param key
     * @return
     */
    public static Map<Object, Object> hgetall(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    // List（列表）

    /**
     * 实现命令：LPUSH key value，将一个值 value插入到列表 key的表头
     *
     * @return long
     * @Param [key, value]
     */
    public static long lpush(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 实现命令：LPOP key，移除并返回列表 key的头元素。
     *
     * @return java.lang.String
     * @Param [key]
     */
    public static String lpop(String key) {
        return (String) redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 实现命令：RPUSH key value，将一个值 value插入到列表 key的表尾(最右边)。
     *
     * @return long
     * @Param [key, value]
     */
    public static long rpush(String key, String value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     *  * 获得key数组里面key2元素的索引
     *  * @param key
     *  * @param key2
     *  * @return
     *
     */
    public static Long rank(String key, Object key2) {
        return redisTemplate.opsForZSet().rank(key, key2);
    }

    /**
     *  * 有序集合添加
     *  *
     *  * @param key
     *  * @param value
     *  * @param scoure
     *
     */
    public static void zAdd(String key, Object value, double scoure) {
        redisTemplate.opsForZSet().add(key, value, scoure);
    }

    /**
     *  * 获得key数组里面key2元素的排序值
     *  * @param key
     *  * @param key2
     *  * @return
     *
     */
    public static double score(String key, Object key2) {
        return redisTemplate.opsForZSet().score(key, key2);
    }

    /**
     *  * 从高到低的排序集中获取从头(start)到尾(end)内的元素。
     *  * @param key
     *  * @param start
     *  * @param end
     *  * @return
     *
     */
    public static Set<Object> reverseRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     *  * 从高到低的排序集中获取从头(start)到尾(end)内的元素。
     *  * @param key
     *  * @param start
     *  * @param end
     *  * @return
     *
     */
    public static void zRemove(String key) {
        redisTemplate.opsForZSet().remove(key);
    }

    /**
     * 判断某个key是否存在
     * @param key 要判断的可以
     * @return true 存在
     */
    public static Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }
}
